home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / exampleCode / csg / csg-paper < prev    next >
Encoding:
Text File  |  1994-08-02  |  9.4 KB  |  232 lines

  1.  
  2.              toolbox/src/exampleCode/csg csg-paper
  3.  
  4.                         Constructive Solid Geometry
  5.  
  6.  
  7.  
  8.                Stencil planes and solid geometry applications
  9.     
  10.                               by Kurt Akeley
  11.  
  12.  
  13. References
  14. ----------
  15.  
  16.   1. "Near Real-Time CSG Rendering using Tree Normalization and Geometric
  17.       Pruning."  Jack Goldfeather, Steven Molnar, Greg Turk, and Henry Fuchs.
  18.  
  19.   2. "Parallel Pixel Algorithms for Constructive Solid Geometry."  Jim Clark
  20.       and Paul Haeberli.
  21.  
  22. Background
  23. ----------
  24.  
  25. CSG stands for constructive solid geometry.  A CSG object is constructed
  26. of unions and intersections of proper primitive solids and their inverses.
  27. For example, a sphere with a circular hole 'drilled' in it can be constructed
  28. by intersecting the inverse of a cylinder with a sphere (thus subtraction
  29. is accomplished by intersection with an inverse).
  30.  
  31. Our proposed algorithm requires that the CSG equation be first reduced to
  32. is normal form.  This is the equivalent of reducing a boolean equation to
  33. disjunctive normal form, a sum of products.  CSG operators union and
  34. intersection are equivalent to sum and product boolean operators.  It is
  35. possible and desirable to eliminate unnecessary terms from this normalized
  36. equation [1].
  37.  
  38. Some Preliminaries
  39. ------------------
  40.  
  41. Crucial to the understanding of our CSG algorithm is the recognition that
  42. no new surfaces are created by the union and intersection of primitives.
  43. I.e., the surfaces of the final object are a subset of the surfaces of the
  44. primitives used to compose it.  Also, let's start by considering only
  45. primitives that are proper convex solids.  These solids are represented
  46. as sets of planer polygons.  Proper polygonal surfaces separate space into
  47. two subspaces, one 'inside' and one 'outside'.  Thus a proper polygon surface
  48. has no holes in it, and does not intersect itself.  The polygonal surface
  49. is convex if any line that passes through the 'inside' volume intersects
  50. the surface exactly twice (once going in, once going out).
  51.  
  52. The Algorithm
  53. -------------
  54.  
  55. Given the above, a very simple algorithm for computing a correct CSG
  56. projection (image) is possible:
  57.  
  58.     Along each line of sight (i.e. at each pixel)
  59.  
  60.     1.  Compute the color and depth of each surface that remains
  61.         after all inversions and intersections are completed.
  62.  
  63.     2.  Choose the nearest color/depth pair.
  64.  
  65. A high-level implementation of this algorithm is:
  66.  
  67.     1.    For every potentially visible primitive polygon, create a
  68.     projection (color and depth) in a temporary buffer.
  69.  
  70.     2.    Test each pixel in this projection against the volumes with which
  71.     it is being intersected.  Force the z value of pixels that don't
  72.     pass all the tests to infinity.
  73.  
  74.     3.    Merge all of these single-polygon images into an accumulation
  75.     buffer, selecting the nearer color/z pair at each pixel.
  76.  
  77. Just as back-facing polygons are never visible in a Z-buffer image, they
  78. also cannot be visible in a CSG image.  Thus, in step 1 above, the
  79. potentially visible polygons are those that are front-facing.  Unless,
  80. of course, the volume is inverted, in which case only back-facing polygons
  81. are potentially visible (because back-facing polygons form the surface
  82. that transistions from 'outside' to 'inside' along the view path).
  83.  
  84. Regarding step 2, each pixel in the temporary buffer is either inside or
  85. outside every primitive with which it is intersected.  Because all
  86. primitives are convex, they intersect each line of sight (pixel) either
  87. twice or not at all (note 1).  The pixel in the temporary buffer is
  88. inside if only one intersection falls between the eyepoint and the pixel.
  89. It is outside if both or neither fall in this space, or if the pixel is
  90. not intersected.
  91.  
  92. The test in step 2 above involves first determining whether the temporary
  93. buffer pixel is inside or outside each primitive (with which it is to be
  94. intersected), then determining whether it should have been inside or
  95. ourside.  It should be outside if it is being intersected with the inverse
  96. of a primitive volume, inside otherwise.  Pixels that fail the test are
  97. effectively eliminated from the temporary image by having their depth (z)
  98. values forced to infinity.  These pixels will never be chosen during the
  99. merge into the accumulation buffer.
  100.  
  101. The final step 2 note: (something about the expresion)
  102.  
  103. Some optimizations to this algorithm are possible:
  104.  
  105.     1.    It is not necessary to render each polygon individually.  It is
  106.     necessary only to insure that the temporary buffer has at most one
  107.     surface sample in each pixel.  With convex primitives this can be
  108.     accomplished by rendering each primitive once, eliminating either all
  109.     front-facing polygons (if the volume is inverted) or all back-facing
  110.     polygons (if it is not).
  111.  
  112.     2.    Only temporary buffer pixels that have non-infinite depths need
  113.     be merged into the accumulation buffer.  Although a pixel-by-pixel
  114.     test would save no effort, it is possible to limit the merge to
  115.     the screen-aligned buffer region that was modifed by the rendered
  116.     primitive.  These buffer boundries can be maintained with minimal
  117.     effort during the render operation.
  118.  
  119.     3.    It is not necessary to compute or store color values during
  120.     rendering to the temporary buffer.  Rather, render only depth
  121.     values, and merge these into the depth portion of the accumulation
  122.     buffer.  When the accumulation is completed, re-render each polygon
  123.     in the scene, replacing color in the accumulation buffer only when
  124.     the depth of the rendered pixel EXACTLY MATCHES the depth in the
  125.     accumulation buffer.
  126.  
  127.     At the cost of re-rendering each polygon only once, both the color
  128.     calculation and storage are saved throughout the execution.
  129.  
  130. Pseudo-code Implementation
  131. --------------------------
  132.  
  133.     initialize the accumulation buffer (background color, near-infinite z)
  134.     initialize the tmp buffer (infinite z, zero count)
  135.     for (each primitive) {
  136.     initialize the bound-measuring hardware
  137.     if (primitive is inverted)
  138.         render the back-facing primitive depth values into the tmp buffer
  139.     else
  140.         render the front-facing primitive depth values into the tmp buffer
  141.     transfer measured primitive bounds to the bound-limit hardware
  142.         (allow NO changes to the tmp buffer outside the bounds)
  143.     for (each intersecting primitive) {
  144.         render just the depth values
  145.         for (each rendered pixel) {
  146.         increment the tmp buffer pixel counter if rendered depth
  147.             is between the eyepoint (zero) and the depth value
  148.             in the temporary buffer
  149.         do NOT replace the depth value in the tmp buffer
  150.         }
  151.         for (each pixel in the bounded region) {
  152.         if (intersecting primitive is inverted) {
  153.             if (count is 1)
  154.             force tmp buffer z value to infinity
  155.         } else if (not inverted) {
  156.             if (count is 0 or 2)
  157.             force tmp buffer z value to infinity
  158.         }
  159.         }
  160.     }
  161.     for (each pixel in the bounded region) {
  162.         if (depth is less than corresponding depth in accumulation)
  163.         replace accumulation buffer depth with tmp depth
  164.         set tmp buffer depth to infinity
  165.         set tmp buffer count to zero
  166.     }
  167.     disable bound-limit hardware (allow changes throughout the
  168.         tmp buffer area)
  169.     }
  170.     for (each primitive) {
  171.     render with color and depth
  172.     for (each rendered pixel) {
  173.         if (depth matches accumulation buffer depth)
  174.         replace accumulation buffer color with new color
  175.     }
  176.     }
  177.  
  178. Non-convex Primitives
  179. ---------------------
  180.  
  181. The surface of a convex volume is intersected twice by a line that passes
  182. through the 'inside'.  We can extend the notion of convexity to include
  183. more complex volumes by defining a convexity number.  This number is the
  184. maximum number of intersections that a line passing through the 'inside'
  185. can have with the surface, divided by two.  Thus simple convex volumes
  186. have a convexity of one.  A taurus (do-nut) has a convexity of two.
  187. We speak in general of k-convex volumes, where k is the convexity number.
  188.  
  189. Our algorithm is easily extended to k-convex primitives.  Two issues need
  190. to be addressed:
  191.  
  192.     1.    A k-convex primitive must be rendered into the temporary buffer
  193.     2k times to insure that each potential surface is given the
  194.     opportunity to be visible.
  195.  
  196.     2.    The inside/outside test must be extended to work with more complex
  197.     volumes.
  198.  
  199. The first issue is handled by providing a mechanism that, at each pixel,
  200. renders the n'th depth value received.  By doing k renders (front-face
  201. and back-face) of a primitive into the temporary buffer, with n set to 1
  202. through k, it is possible to insure that each surface is represented
  203. (note 2).
  204.  
  205. Because we require that our k-convex volumes also have nonself-intersecting
  206. surfaces, we know that a line that passes through the 'inside' of the
  207. volume alternates inside/outside each time it intersects the surface.
  208. Thus, rather than testing for a count of 1 to indicate 'inside', we can
  209. simply check for an odd count.
  210.  
  211. Incorporating these two modifications to the algorithm is left as an
  212. exercise for the reader.
  213.  
  214. Notes
  215. -----
  216.  
  217.     1.    Proper point sampling of polygons during rendering is absolutely
  218.     required by this CSG algorithm.  Adjacent polygons must neither
  219.     share any pixels, nor leave any pixels unfilled (i.e. they must
  220.     abut exactly).  If this is done correctly, even pixels whose sample
  221.     point is exactly on a silhouette edge of the polygonal volume will
  222.     correctly register two hits (even though the ray does not pass
  223.     through the 'inside' volume).
  224.  
  225.     2.    Not all pixels will receive k distinct values.  It is very possible
  226.     that none will.  A possible optimization involves determining the
  227.     maximum number of times that any pixel is intersected by the
  228.     primitive, and doing this number of passes (regardless of the
  229.     convexity of the primitive).
  230.  
  231.  
  232.